#include <sum_gpio.h>
#include <sum_rcu.h>
#include <sum_usart.h>
#include <util_abs.h>
#include <util_trans.h>

#define APB2_FREQ_DEFAULT 8000000
#define ABS_LOW_ZERO_AMOUNT 12

// RCU中将GPIOA和USART0上电
static void _enable_gpioa_usart0(void) {
	rcu_apb2_s apb2 = {
		.apb2_0_7.GPIOA = 1,
		.apb2_8_15.USART0 = 1,
	};
	rcu_apb2_en_di(apb2);
}

// 配置A9为AF输出，A10为浮空输入。
static void _setup_gpafio(void) {
	gpio_ctl_8_15_s ctl = {
		// A9的配置：低速输出、AF、推挽
		.pin9_ctl = GPIO_OUT_AF_PP_2MHZ,
		// A10的配置：输入、浮空
		.pin10_ctl = GPIO_IN_FLOAT,
	};
	gpio_setup_pin_8_15(GPIOA_Q, ctl);
}

// 使能USART0本身，以及其发送功能。
static void _enable_usart0_send(void) {
	usart_ctl0_expl_s ctl0 = {
		.trans_en = 1,
		.usart_en = 1,
	};
	usart_setup_0(USART0_Q, ctl0);
}

// 向串口阻塞发送1字节的函数，也是trans_write系列函数的参数。
static void _send(u32_s byte) {
	usart_wb_byte(USART0_Q, byte);
}

// 检查绝对值函数。若发现错误，会输出错误信息。
static void _verify_abs(void) {
	trans_write_str("Verify sm_abs().\n", _send);
	i32_s i = 0;
	do {
		u32_s sm_abs_i = sm_abs(i);
		u32_s normal_abs_i = (i >= 0 ? i : -i);
		if (sm_abs_i != normal_abs_i) {
			trans_write_str("Error! abs(", _send);
			trans_write_idec(i, _send);
			trans_write_str(") = ", _send);
			trans_write_udec(normal_abs_i, _send);
			trans_write_str(", but sm_abs(", _send);
			trans_write_idec(i, _send);
			trans_write_str(") = ", _send);
			trans_write_udec(sm_abs_i, _send);
			trans_write_str("!\n", _send);
			return;
		}

		// 有符号整数溢出是未定义行为，因此先使用无符号整数运算再赋值给i。
		u32_s u = i;
		u += (1 << ABS_LOW_ZERO_AMOUNT);
		i = u;
	} while (i != 0);
	trans_write_str("All right!\n", _send);
}

__attribute__((noreturn, section(".MAIN"))) void user_main(void) {
	// 没有全局变量，不需要scatter_load。
	// mem_scatter_load();
	_enable_gpioa_usart0();
	_setup_gpafio();
	usart_set_baud_rate(USART0_Q, 115200, APB2_FREQ_DEFAULT);
	_enable_usart0_send();

	_verify_abs();
	while (1)
		;
}
